<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="shortcut icon" href="">
    <title>Boids</title>
    <style type="text/css">
        body {
            background-color: #eccc68;
        }

        canvas {
            width: 400px;
            height: 300px;
            border: 1px solid black;
        }
    </style>
</head>

<body>
    <script type="module">
        import {createCanvas, vector28Angle, vector2, vector2random, key, animation, mouse, curve, circle, rect, line, fill, stroke, frame} from './spring/board.js'

        const width = 1200, height = 800

        let aligment_ = 1, cohesion_ = 1, separation_ = 1
        class Boid {
            constructor() {
                this.position = vector2(Math.random() * width, Math.random() * height)
                this.velocity = vector2random()
                this.velocity.length = (Math.random() * 2 + 2)
                this.acceleration = vector2()
                this.maxForce = .42
                this.maxSpeed = 8
                this.tail = []
            }
            // 排列
            align(boids) {
                const perceptionRadius = 50, steering = vector2()
                let total = 0
                for (let other of boids) {
                    if (other != this && this.position.clone().sub(other.position).length < perceptionRadius) {
                        steering.add(other.velocity)
                        total++
                    }
                }
                if (total > 0) {
                    steering.mul(1/total)
                    steering.length = this.maxSpeed
                    steering.sub(this.velocity)
                    steering.limit(this.maxForce)
                }
                return steering
            }
            // 凝聚
            cohesion(boids) {
                const perceptionRadius = 50, steering = vector2()
                let total = 0
                for (let other of boids) {
                    if (other != this && this.position.clone().sub(other.position).length < perceptionRadius) {
                        steering.add(other.position)
                        total++
                    }
                }
                if (total > 0) {
                    steering.mul(1/total)
                    steering.sub(this.position)
                    steering.length = this.maxSpeed
                    steering.sub(this.velocity)
                    steering.limit(this.maxForce)
                }
                return steering
            }
            // 分离
            separation(boids) {
                const perceptionRadius = 50, steering = vector2()
                let total = 0
                for (let other of boids) {
                    let d = this.position.clone().sub(other.position).length
                    if (other != this && d < perceptionRadius) {
                        let diff = this.position.clone().sub(other.position).mul(1/d)
                        steering.add(diff)
                        total++
                    }
                }
                if (total > 0) {
                    steering.mul(1/total)
                    steering.length = this.maxSpeed
                    steering.sub(this.velocity)
                    steering.limit(this.maxForce)
                }
                return steering
            }

            flock(boids) {
                /*
                */
                let alignment = this.align(boids)
                this.acceleration.add(alignment.mul(aligment_))

                let cohesion = this.cohesion(boids)
                this.acceleration.add(cohesion.mul(cohesion_))

                let separation = this.separation(boids)
                this.acceleration.add(separation.mul(separation_))
            }

            edge() {
                if (this.position.x > width) {
                    this.position.x = 0
                    this.tail.forEach( t => {
                        t.copy(this.position)
                    })
                    // this.tail.copy(this.position)
                }
                if (this.position.y > height) {
                    this.position.y = 0
                    this.tail.forEach( t => {
                        t.copy(this.position)
                    })
                    // this.tail.copy(this.position)
                }
                if (this.position.x < 0) {
                    this.position.x = width
                    this.tail.forEach( t => {
                        t.copy(this.position)
                    })
                    // this.tail.copy(this.position)

                }
                if (this.position.y < 0) {
                    this.position.y = height
                    this.tail.forEach( t => {
                        t.copy(this.position)
                    })
                    // this.tail.copy(this.position)
                }
            }

            update() {
                this.position.add(this.velocity)
                this.velocity.add(this.acceleration)
                this.velocity.limit(this.maxSpeed)
                this.acceleration.mul(0)
                this.tail.push(this.position.clone())
                if (this.tail.length > 5) {
                    this.tail.splice(0, 1)
                }
            }

            show() {
                circle(this.position.x, this.position.y, 8, 20)
                fill()
                curve(this.tail, stroke)
            }
        }

        createCanvas(width / 2, height / 2)

        // frame(10)
        const boids = []
        for (let i = 0; i < 150; ++i) {
            boids.push(new Boid())
        }
        function draw() {
            boids.forEach( boid => {
                boid.edge()
                boid.flock(boids)
                boid.update()
                boid.show()
            })

            if (key.isPress) {
                // aligment
                if (key.keypress['a']) {
                    if (aligment_ >= 0.1) {
                        aligment_ -= 0.1
                    }
                }
                if (key.keypress['q']) {
                    if (aligment_ <= 4.9) {
                        aligment_ += 0.1
                    }
                }
                // cohesion
                if (key.keypress['s']) {
                    if (cohesion_ >= 0.1) {
                        cohesion_ -= 0.1
                    }
                }
                if (key.keypress['w']) {
                    if (cohesion_ <= 4.9) {
                        cohesion_ += 0.1
                    }
                }
                // separation
                if (key.keypress['d']) {
                    if (separation_ >= 0.1) {
                        separation_ -= 0.1
                    }
                }
                if (key.keypress['e']) {
                    if (separation_ <= 4.9) {
                        separation_ += 0.1
                    }
                }
                console.log(aligment_, cohesion_, separation_)
            }
        }
        animation(draw)
    </script>
</body>

</htmlg